package org.lds.logger.impl;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.lds.logger.AbstractLogger;
import org.lds.logger.config.Configuration;
import org.lds.logger.config.appender.Appender;
import org.lds.logger.config.appender.async.AsyncAppenderGroup;
import org.lds.logger.config.filter.AbstractAppenderFilter;
import org.lds.logger.config.level.Level;
import org.lds.logger.event.LoggerEvent;
import org.lds.logger.util.Utils;

import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoggerImpl extends AbstractLogger {
    private Configuration configuration;
    private String name;
    private Level level;

    public LoggerImpl(String name, Level level, Configuration configuration) {
        this.name = name;
        this.level = level;
        this.configuration = configuration;
    }

    @Override
    protected void log(Level level, String message) {
        // 1. 构造loggerEvent
        LoggerEvent loggerEvent = LoggerEvent.builder()
                .name(name)
                .level(level)
                .message(message)
                .build();

        // 2. 日志级别过滤
        if (shouldFilter(level)) return;

        // 3. 异步appender
        asyncAppend(loggerEvent);

        // 4. 同步appender
        syncAppend(loggerEvent);
    }

    private boolean shouldFilter(Level loggerEventLevel) {
        return loggerEventLevel.getCode() < level.getCode();
    }

    private void syncAppend(LoggerEvent loggerEvent) {
        List<Appender> appenderList = configuration.getAppenderList();
        if (CollectionUtils.isEmpty(appenderList)) return;

        for (Appender appender : appenderList) {
            try {
                // 2.1 局部AppenderFilter过滤消息
                AbstractAppenderFilter abstractAppenderFilter = appender.getAppenderFilter();
                if (abstractAppenderFilter != null && abstractAppenderFilter.shouldFilter(loggerEvent)) continue;

                // 2.2 处理消息
                appender.append(loggerEvent);
            } catch (Throwable e) {
                // 吞掉异常 不允许影响其他Appender
                Utils.report("appender error. appender=" + appender.getName() + ",error=" + e.getMessage());
            }
        }
    }

    private void asyncAppend(LoggerEvent loggerEvent) {
        AsyncAppenderGroup asyncAppenderGroup = configuration.getAsyncAppenderGroup();
        if (asyncAppenderGroup == null) return;

        asyncAppenderGroup.append(loggerEvent);
    }

}
